package com.supreme.cacheserver.service;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.supreme.common.dto.OmsDept;
import com.supreme.commonentity.mysql.primary.MBTest;
import com.supreme.commonentity.mysql.primary.SysDept;
import com.supreme.commonmybatis.mapper.SysDeptMapper;
import com.supreme.commonmybatis.mapper.TestMapper;
import com.supreme.commonmybatis.service.quick.ExtSysDeptService;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.StopWatch;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;

@Service
public class OmsDeptService {

    @Resource
    private RedisTemplate<String, OmsDept> redisTemplate;

    @Resource
    private SysDeptMapper sysDeptMapper;

    @Resource
    private ExtSysDeptService extSysDeptService;

    @Resource
    private SqlSessionFactory sqlSessionFactory;

    public List<OmsDept> getOmsDeptListFromRedis(String key) {
        return redisTemplate.opsForList().range(key, 0, -1);
    }

    public long loopFindSysDeptFromLocal(List<SysDept> sysDeptList, Integer queryType) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        Map<Object, Object> deptHash = redisTemplate.opsForHash().entries("DEPT_HASH");
        List<OmsDept> omsDeptList = redisTemplate.opsForList().range("DEPT_LIST", 0, -1);

        int loopCount = 0;
        switch (queryType) {
            case 1:
                for (SysDept sysDeptItem : sysDeptList) {
                    SysDept sysDept = sysDeptMapper.selectOne(
                            Wrappers.lambdaQuery(SysDept.class).eq(SysDept::getStoreCode, sysDeptItem.getStoreCode())
                    );
                    loopCount++;
                    System.out.println(loopCount + " CODE = " + sysDept.getStoreCode());
                }
                break;

            case 2:
                for (SysDept sysDeptItem : sysDeptList) {
                    OmsDept omsDept = (OmsDept) deptHash.get(sysDeptItem.getStoreCode());
                    loopCount++;
                    System.out.println(loopCount + " CODE = " + omsDept.getStoreCode());
                }
                break;

            case 3:
                for (SysDept sysDeptItem : sysDeptList) {
                    OmsDept omsDept = (OmsDept) redisTemplate.opsForHash().get("DEPT_HASH", sysDeptItem.getStoreCode());
                    loopCount++;
                    System.out.println(loopCount + " CODE = " + omsDept.getStoreCode());
                }
                break;

            case 4:
                for (SysDept sysDeptItem : sysDeptList) {
                    Optional<OmsDept> optionalOmsDept = omsDeptList.parallelStream().filter(omsDept -> Objects.equals(omsDept.getStoreCode(), sysDeptItem.getStoreCode())).findAny();
                    if (optionalOmsDept.isPresent()) {
                        OmsDept omsDept = optionalOmsDept.get();
                        loopCount++;
                        System.out.println(loopCount + " CODE = " + omsDept.getStoreCode());
                    }
                }
                break;

            case 5:
                for (SysDept sysDeptItem : sysDeptList) {
                    Optional<OmsDept> optionalOmsDept = omsDeptList.stream().filter(omsDept -> Objects.equals(omsDept.getStoreCode(), sysDeptItem.getStoreCode())).findAny();
                    if (optionalOmsDept.isPresent()) {
                        OmsDept omsDept = optionalOmsDept.get();
                        loopCount++;
                        System.out.println(loopCount + " CODE = " + omsDept.getStoreCode());
                    }
                }
                break;

            case 6:
                for (SysDept sysDeptItem : sysDeptList) {
                    Optional<OmsDept> optionalOmsDept = omsDeptList.stream().filter(omsDept -> Objects.equals(omsDept.getStoreCode(), sysDeptItem.getStoreCode())).findFirst();
                    if (optionalOmsDept.isPresent()) {
                        OmsDept omsDept = optionalOmsDept.get();
                        loopCount++;
                        System.out.println(loopCount + " CODE = " + omsDept.getStoreCode());
                    }
                }
                break;
        }


        stopWatch.stop();
        return stopWatch.getTotalTimeMillis();
    }

    public long batchInsertSysDeptBySingle(List<SysDept> sysDeptList) {
        Long selectCount = sysDeptMapper.selectCount(Wrappers.emptyWrapper());
        if (selectCount > 0) {
            sysDeptMapper.truncateTable();
        }

        StopWatch stopWatch = new StopWatch("singleInsert");
        stopWatch.start();
        for (SysDept sysDept : sysDeptList) {
            sysDeptMapper.insert(sysDept);
        }
        stopWatch.stop();
        return stopWatch.getTotalTimeMillis();
    }

    public long batchInsertSysDeptByMapper(List<SysDept> sysDeptList) {
        Long selectCount = sysDeptMapper.selectCount(Wrappers.emptyWrapper());
        if (selectCount > 0) {
            sysDeptMapper.truncateTable();
        }

        StopWatch stopWatch = new StopWatch("singleInsert");
        stopWatch.start();
        sysDeptMapper.batchInsert(sysDeptList);
        stopWatch.stop();
        return stopWatch.getTotalTimeMillis();
    }

    @Transactional(rollbackFor = Exception.class)
    public long batchInsertSysDeptByService(List<SysDept> sysDeptList) {
        Long selectCount = sysDeptMapper.selectCount(Wrappers.emptyWrapper());
        if (selectCount > 0) {
            sysDeptMapper.truncateTable();
        }

        StopWatch stopWatch = new StopWatch("singleInsert");
        stopWatch.start();
        extSysDeptService.saveBatch(sysDeptList, 500);
        stopWatch.stop();
        return stopWatch.getTotalTimeMillis();
    }

    @Transactional(rollbackFor = Exception.class)
    public long batchInsertSysDeptBySqlSession(List<SysDept> sysDeptList) {
        Long selectCount = sysDeptMapper.selectCount(Wrappers.emptyWrapper());
        if (selectCount > 0) {
            sysDeptMapper.truncateTable();
        }

        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
        SysDeptMapper sessionSysDeptMapper = sqlSession.getMapper(SysDeptMapper.class);

        StopWatch stopWatch = new StopWatch("singleInsert");
        stopWatch.start();

        for (int i = 0; i < sysDeptList.size(); i++) {
            SysDept sysDept = sysDeptList.get(i);
            sessionSysDeptMapper.insert(sysDept);
            if (i % 1000 == 999) {
                sqlSession.flushStatements();
            }
        }
        boolean synchronizationActive = TransactionSynchronizationManager.isSynchronizationActive();
        System.out.println("synchronizationActive = " + synchronizationActive);
        sqlSession.commit(!synchronizationActive);

        sqlSession.close();

        stopWatch.stop();
        return stopWatch.getTotalTimeMillis();
    }
}
